﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web;
using System.Web.Http;
using eDonkeyAPI.Models;
using System.ServiceModel;

namespace eDonkeyAPI.Controllers
{
    [ServiceContract]
    public class CoursesController : ApiController
    {
        private mydbEntities db = new mydbEntities();

        [ActionName("Faculty")]
        [HttpGet]
        public List<String> Faculty()
        {
            List<string> l = db.Courses.Select(c => c.Faculty).Distinct().ToList();
            return l;
        }


        [ActionName("GetCourses")]
        [HttpGet]
        // GET api/Courses
        public IEnumerable<Course> GetCourses([FromUri]List<string> coursesNumbers = null, int count=25, int page=1)
        {
            if (coursesNumbers == null)
            {
                return db.Courses.AsEnumerable();
            }
            List<Course> coursesList = new List<Course>();
            if (coursesNumbers == null)
            {
                return null;
            }
            foreach (string courseNumber in coursesNumbers)
            {
                List<Course> list = new List<Course>();
                list = db.Courses.Where(c => (c.Number == courseNumber)).OrderBy(c => c.Id).Skip(count * (page - 1)).Take(count).ToList();
                coursesList.AddRange(list);
            }
            return coursesList;
        }

        [HttpGet]
        public List<Group> MyGroups([FromUri]List<string> courses = null)
        {
            List<Group> groups = new List<Group>();
            foreach (string course in courses)
            {
                ICollection<Group> igroups = db.Courses.Include(c => c.Groups).FirstOrDefault(c => c.Number == course).Groups;
                if (igroups == null || igroups.Count == 0)
                {
                    continue;
                }
                foreach (Group group in igroups)
                {
                    //group.PlaceTimes = null;
                    group.PlaceTimes = db.PlaceTimes.Where(pt => pt.GroupId == group.Id).ToList();
                    if (group.PlaceTimes != null)
                    {
                        foreach (PlaceTime pt in group.PlaceTimes)
                        {
                            pt.Group = null;
                        }
                    }
                    group.Course.Groups = null;
                    group.Course.Semester = null;
                    group.Course.Teacher = null;
                    groups.Add(group);
                }
            }
            return groups;
        }

        // GET api/Courses/5
        [OperationContract]
        [CyclicReferencesAware(true)]
        public List<Course> GetCourse(int temp,string number="0", string name = "", double? points = null,
                                      string startTime = "", string endTime = "", string day = "",
                                      string teacherFirstName = "", string teacherLastName = "",
                                      [FromUri]List<string> faculty = null, string sameWord = "True",
                                      string examDate="", string term ="A",
                                      int count = 25, int page = 1)
        {
            //Course course;
            List<Course> courses = null;
            DateTime? date = null;
            if (!string.IsNullOrEmpty(examDate))
                date = Convert.ToDateTime(examDate);
            if (sameWord == "True")
            {
                
                courses = db.Courses.Include(c => c.Teacher).Include(c => c.Groups)
                                 .Where(x => ((number == "0" || x.Number == number) &&
                                                       (string.IsNullOrEmpty(name) || x.Name == name) &&
                                                       (points == null || x.Points == points) &&
                                                       (string.IsNullOrEmpty(teacherFirstName) || x.Teacher.FirstName == teacherFirstName) &&
                                                       (string.IsNullOrEmpty(teacherLastName) || x.Teacher.LastName == teacherLastName) &&
                                                       (string.IsNullOrEmpty(examDate) || (term == "A" && x.TermA == date) || (term == "B" && x.TermB == date)) &&
                                                       (faculty.Count == 0 || (faculty.Contains(x.Faculty)))
                                                       )).OrderBy(c => c.Id).Skip(count * (page - 1)).Take(count).ToList();
            }
            else
            {
                courses = db.Courses.Include(c => c.Teacher).Include(c => c.Groups)
                                 .Where(x => ((number == "0" || x.Number == number) &&
                                                       (string.IsNullOrEmpty(name) || x.Name.Contains(name)) &&
                                                       (points == null || x.Points == points) &&
                                                       (string.IsNullOrEmpty(teacherFirstName) || x.Teacher.FirstName.Contains(teacherFirstName)) &&
                                                       (string.IsNullOrEmpty(teacherLastName) || x.Teacher.LastName.Contains(teacherLastName)) &&
                                                       (string.IsNullOrEmpty(examDate) || (term == "A" && x.TermA == date) || (term == "B" && x.TermB == date)) &&                                                       
                                                       (faculty.Count == 0 || (faculty.Contains(x.Faculty)))
                                                       )).OrderBy(c => c.Id).Skip(count * (page - 1)).Take(count).ToList();
            }
            foreach (Course course in courses)
            {
                foreach (var group in course.Groups)
                {
                    group.Teacher = db.Teachers.Single(t => t.Id == group.TeacherId);
                    group.PlaceTimes = db.PlaceTimes.Where(pt => pt.GroupId == group.Id).ToList();
                }
                if (course != null)
                {
                    course.Teacher.Courses = null;
                    foreach (var group in course.Groups)
                    {
                        group.Course = null;
                        //group.Teacher = null;
                        if (group.Teacher != null)
                        {
                            //group.Teacher.Courses = null;
                            group.Teacher.Groups = null;
                        }
                        if (group.PlaceTimes != null)
                        {
                            foreach (PlaceTime pt in group.PlaceTimes)
                            {
                                pt.Group = null;
                            }
                        }
                    }
                }
            }

            List<Course> tempCourseList = new List<Course>();
            foreach (Course course in courses)
            {
                if (isCourseHasTime(course, startTime, endTime, day) == true)
                {
                    tempCourseList.Add(course);
                }
            }
            return tempCourseList;
        }

        // PUT api/Courses/5
        public HttpResponseMessage PutCourse(int id, Course course)
        {
            if (ModelState.IsValid && id == course.Id)
            {
                db.Entry(course).State = EntityState.Modified;

                try
                {
                    db.SaveChanges();
                }
                catch (DbUpdateConcurrencyException)
                {
                    return Request.CreateResponse(HttpStatusCode.NotFound);
                }

                return Request.CreateResponse(HttpStatusCode.OK);
            }
            else
            {
                return Request.CreateResponse(HttpStatusCode.BadRequest);
            }


        }

        // POST api/Courses
        public HttpResponseMessage PostCourse(Course course)
        {
            if (ModelState.IsValid)
            {
                db.Courses.Add(course);
                db.SaveChanges();

                HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.Created, course);
                response.Headers.Location = new Uri(Url.Link("DefaultApi", new { id = course.Id }));
                return response;
            }
            else
            {
                return Request.CreateResponse(HttpStatusCode.BadRequest);
            }
        }

        // DELETE api/Courses/5
        public HttpResponseMessage DeleteCourse(int id)
        {
            Course course = db.Courses.Find(id);
            if (course == null)
            {
                return Request.CreateResponse(HttpStatusCode.NotFound);
            }

            db.Courses.Remove(course);

            try
            {
                db.SaveChanges();
            }
            catch (DbUpdateConcurrencyException)
            {
                return Request.CreateResponse(HttpStatusCode.NotFound);
            }

            return Request.CreateResponse(HttpStatusCode.OK, course);
        }

        protected override void Dispose(bool disposing)
        {
            db.Dispose();
            base.Dispose(disposing);
        }

        public bool isCourseHasTime(Course course, string fromTime = "", string toTime = "", string inDay = "")
        {
            ICollection<Group> igroups = db.Courses.Include(c => c.Groups).FirstOrDefault(c => c.Number == course.Number).Groups;
            if ((igroups == null || igroups.Count == 0) && (fromTime.Length != 0 || toTime.Length != 0 || inDay.Length != 0))
            {
                return false;
            }
            if (igroups == null || igroups.Count == 0)
            {
                return true;
            }

            foreach (Group group in igroups)
            {
                group.PlaceTimes = db.PlaceTimes.Where(pt => pt.GroupId == group.Id).ToList();
                foreach (PlaceTime placeTime in group.PlaceTimes)
                {
                    if (string.IsNullOrWhiteSpace(placeTime.StartTime) || string.IsNullOrWhiteSpace(placeTime.Duration))
                    {
                        continue;
                    }
                    int endTime = SchedulerController.convertHourToIndex(placeTime.StartTime) + 2 * Convert.ToInt32(placeTime.Duration);
                    if ((fromTime.Length == 0 || SchedulerController.convertHourToIndex(placeTime.StartTime) == SchedulerController.convertHourToIndex(fromTime)) &&
                        (toTime.Length == 0 || endTime == SchedulerController.convertHourToIndex(toTime.ToString())) &&
                        (inDay.Length == 0 || placeTime.Day.Contains(inDay)))
                    {
                        return true;
                    }
                }
            }
            return false;
        }

       

        [HttpGet]
        public List<string> GetCoursesWithTime([FromUri]string fromTime = "", [FromUri]string toTime = "", [FromUri]string inDay = "")
        {
            List<string> coursesNames = new List<string>();
            List<PlaceTime> placeTimes = new List<PlaceTime>();
            List<PlaceTime> placeTimesHasEndTime = new List<PlaceTime>();
            placeTimes = db.PlaceTimes.Where(x => ((string.IsNullOrEmpty(fromTime) || x.StartTime.Contains(fromTime)) &&
                                                   (string.IsNullOrEmpty(inDay) || x.Day.Contains(inDay)))).ToList();
            foreach (PlaceTime placeTime in placeTimes)
            {
                if (string.IsNullOrWhiteSpace(placeTime.StartTime) || string.IsNullOrWhiteSpace(placeTime.Duration))
                {
                    continue;
                }
                int endTime = SchedulerController.convertHourToIndex(placeTime.StartTime) + 2 * Convert.ToInt32(placeTime.Duration);
                if ((toTime.Length == 0 || endTime == SchedulerController.convertHourToIndex(toTime)))
                {
                    List<Group> groups = new List<Group>(db.Groups.Where(x => (x.Id == placeTime.GroupId)).ToList());
                    Group group = new Group();
                    if (groups != null && groups.Count > 0)
                    {
                        group = groups[0];
                    }
                    List<Course> courses = new List<Course>(db.Courses.Where(x => (x.Id == group.CourseId)).ToList());
                    Course course = new Course();
                    if (courses != null && courses.Count > 0)
                    {
                        course = courses[0];
                    }
                    coursesNames.Add(course.Name);
                }
            }
            return coursesNames;
        }

    }
}